# @FileName  : film.py
# @Time      : 2025/2/6 7:18
# @Author    : LuZhaoHui
# @Software  : PyCharm

from serial.serialutil import SerialException
# from functools import partial
from filmUI import Ui_MainWindow
from stopUI import Ui_DialogStop
from startUI import Ui_DialogPrompt
# from ui.promptUI import Ui_FormPrompt
# from ui.image import Ui_FormImage

from screen import *
from conf import *
from com import *
from scara import *
from str import *
import sys, copy

VER = '1.5.7.14'


def show_current_time(time_label):
    # 获取系统当前时间
    t = QDateTime.currentDateTime()
    # 设置系统时间的显示格式-状态栏显示
    time_label.setText(t.toString(' yyyy-MM-dd hh:mm:ss dddd'))


'''
class photoImage(QWidget, Ui_FormImage):
    def __init__(self, file):
        super(photoImage, self).__init__()
        self.setupUi(self)
        self.file = file
        self.init()

    def imageFile(self):
        self.labelImage.setText('')
        showLabelImage(self.scrollAreaImage,
                       self.labelImage,
                       os.path.join(IMG_PATH, self.file).replace('\\', '/'),
                       True)

    def init(self):
        self.setWindowTitle('显示图片')
        self.setWindowIcon(QIcon(LOGO))
        # self.setWindowFlags(Qt.WindowType.WindowCloseButtonHint)
        # self.showMaximized()
        self.imageFile()
'''
'''
class PromptRun(QWidget, Ui_FormPrompt):
    def __init__(self, image, info=''):
        super(PromptRun, self).__init__()
        self.setupUi(self)
        self.setWindowFlags(Qt.WindowType.WindowCloseButtonHint)
        # self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        self.info = info
        self.image = image
        self.init()

    def init(self):
        print(self.scrollAreaImage.widget().width())
        if self.info != '':
            self.pushButtonExit.setText(self.info)
        self.scrollAreaImage.setWidgetResizable(True)
        self.labelImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        showLabelImage(self.scrollAreaImage,
                       self.labelImage,
                       os.path.join(IMG_PATH, self.image).replace('\\', '/'),
                       True)
        self.pushButtonExit.clicked.connect(self.exit)
'''


class StartRun(QDialog, Ui_DialogPrompt):
    def __init__(self, image, info=''):
        super(StartRun, self).__init__()
        self.setupUi(self)
        self.setWindowFlags(Qt.WindowType.WindowCloseButtonHint)
        # self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        self.info = info
        self.image = image
        self.init()

    def init(self):
        if self.info != '':
            self.pushButtonExit.setText(self.info)
        self.scrollAreaImage.setWidgetResizable(True)
        self.labelImage.setSizePolicy(QSizePolicy.Expanding, QSizePolicy.Expanding)
        showLabelImage(self.scrollAreaImage,
                       self.labelImage,
                       self.image,
                       True)
        self.pushButtonExit.clicked.connect(self.exit)

    def exit(self):
        self.close()


class StopRun(QDialog, Ui_DialogStop):
    proc_exit = pyqtSignal(int)

    # 停止窗口
    def __init__(self, info, delay, ser):
        super(StopRun, self).__init__()
        self.setupUi(self)
        self.setWindowFlags(Qt.WindowType.WindowCloseButtonHint)
        # self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        self.info = info
        self.delay = delay
        self.ser = ser
        self.init()

    def init(self):
        self.timer = QTimer()
        self.timer.timeout.connect(self.update_timer)
        self.timer.start(1000)
        self.pushButtonExit.clicked.connect(self.exit)

    def closeEvent(self, event):
        print('exit')
        self.proc_exit.emit(self.delay)

    def exit(self):
        self.close()

    def update_timer(self):
        # print('update_timer %d %d %d %d' % (self.delay, self.ser.isEmpty(), self.ser.isOk, self.ser.isArrival))
        if not self.ser.isEmpty() or self.ser.isOk or self.ser.isArrival:
            return
        # 每秒变化
        self.delay -= 1
        self.labelInfo.setText('%s-%d' % (self.info, self.delay))
        if self.delay <= 0:
            self.exit()


class FilmRun(QMainWindow, Ui_MainWindow):
    # 主窗口
    stdoutBak = ''
    stderrBak = ''

    isLink = False
    curWin = -1
    sys_timer = None
    buttonList = []
    windowList = []

    curPos = None

    comPort = ''
    comRate = 9600
    serial_thread = None
    curCodeFile = ''
    code_thread = None
    code_timer = None
    code_begin_time = 0
    arm_mode = 0  # 右臂模式
    # 震动+旋转：定时,状态,初始位置,速度,移动
    code_test_timer = None
    code_act_timer = None
    code_act_state = -1
    code_act_delay = False
    code_act_rate = 0
    code_act_quake_state = 0
    code_act_quake_point = []  # 空无震动
    code_act_quake_space = 0
    code_act_rotate_step = 0  # 0 无旋转
    code_act_ts = 0
    # 当前位置
    act_move_point = []
    act_move_pos = 0
    act_cur_locate = 0
    act_cur_begin_time = 0
    act_cur_tims = [0, 0, 0, 0, 0, 0, 0]
    act_cur_state = [0, 0, 0, 0, 0, 0, 0]

    pointList = []
    codeFilename = ''
    codeTextPos = 0
    codeTextLine = 0
    codeTextNums = 0

    curLogRows = 0

    def __init__(self, parent=None):
        super(FilmRun, self).__init__(parent)
        self.setupUi(self)
        self.init_redirection()
        self.config = FilmConf(FILMCONF)
        self.init_var()
        self.init_time()
        # self.init_serial()
        self.init()
        self.init_ui()
        self.flush_setup()
        self.flush_debug()
        self.show_act()
        self.flush_show()
        if self.config.varConf['StartPrompt']:
            self.proc_code_start()

    def init_redirection(self):
        self.stdoutBak = sys.stdout
        self.stderrBak = sys.stderr

    def reset_redirection(self):
        sys.stdout = self.stdoutBak
        sys.stderr = self.stderrBak

    def closeEvent(self, event, **kwargs):
        if showBoxYes(self, "系统将退出，是否确认?  "):
            event.accept()
        else:
            event.ignore()

    def mousePressEvent(self, event):
        self.curPos = event.globalPos() - self.frameGeometry().topLeft()
        # 判断是否标题栏
        if not self.horizontalLayoutTop.geometry().contains(self.curPos):
            self.curPos = None

    def mouseMoveEvent(self, event):
        if event.buttons() == Qt.MouseButton.LeftButton and self.curPos is not None:
            # 标题栏移动窗口
            self.move(event.globalPos() - self.curPos)

    def exit(self):
        self.reset_redirection()
        if self.sys_timer is not None:
            self.sys_timer.stop()
            del self.sys_timer
            self.sys_timer = None
        # self.serial.disconnect()
        # del self.serial

    # def init_serial(self):
    # self.serial = AsyncSerial()

    def is_debug(self):
        return self.config.varUi['DebugEnable']

    def is_setup(self):
        return self.config.varUi['SetupEnable']

    def is_info(self):
        return self.config.varUi['InfoEnable']

    def init_time(self):
        self.sys_timer = QTimer()
        self.sys_timer.timeout.connect(lambda: show_current_time(self.labelCurTime))
        self.sys_timer.start(1000)
        self.code_test_timer = QTimer()
        self.code_test_timer.timeout.connect(self.update_test_timer)
        self.code_test_timer.stop()

    def init_var(self):
        self.buttonList.clear()
        self.windowList.clear()
        if self.is_debug():
            self.buttonList.append(self.pushButtonDebug)
            self.windowList.append(self.pageDebug)
        self.buttonList.append(self.pushButtonAct)
        self.windowList.append(self.pageAct)
        if self.is_info():
            self.buttonList.append(self.pushButtonInfo)
            self.windowList.append(self.pageInfo)
        if self.is_setup():
            self.buttonList.append(self.pushButtonSetup)
            self.windowList.append(self.pageSetup)
        self.curWin = self.config.varUi['CurWin']
        self.comPort = self.config.varCom['ComPort']
        self.comRate = self.config.varCom['ComRate']
        self.curCodeFile = self.config.varCode['CurCodeFile']

    def get_code_files(self):
        code_files = []
        for f in os.listdir(CODE_PATH):
            name = path_join(CODE_PATH, f)
            if os.path.isfile(name) and f[-5:] == '.code':
                code_files.append(f[:-5])
        return code_files

    # def getButtonActPoint(self, index):
    #     return 'self.pushButtonActPoint%d' % index

    def setButtonActPointText(self, index):
        eval('self.pushButtonActPoint%d.setText(\'%s\')' % (index + 1,
                                                            self.config.varUi['ButtonPointText'][index]))

    def setButtonActPointEnable(self, index):
        eval('self.pushButtonActPoint%d.setEnabled(%s)' % (index + 1,
                                                           str(self.config.varUi['ButtonPointEnable'][index])))

    def showButtonActPointState(self, index, state=0, ts=0):
        state_text = ''
        time_text = ''
        shell = 'QPushButton { background-color: rgb(144, 144, 144); }'
        if self.config.varUi['ButtonPointEnable'][index]:
            # 正常
            state_text = self.config.varUi['ActState'][state]
            time_text = '%d' % ts
            if state == 0:
                # 未动
                shell = 'QPushButton { background-color: rgb(%d, %d, %d); }' % (
                    self.config.varUi['ActPointBackColor0'][0],
                    self.config.varUi['ActPointBackColor0'][1],
                    self.config.varUi['ActPointBackColor0'][2])
            elif state == 1:
                # 操作
                shell = 'QPushButton { background-color: rgb(%d, %d, %d); }' % (
                    self.config.varUi['ActPointBackColor1'][0],
                    self.config.varUi['ActPointBackColor1'][1],
                    self.config.varUi['ActPointBackColor1'][2])
            elif state == 2:
                # 完毕
                shell = 'QPushButton { background-color: rgb(%d, %d, %d); }' % (
                    self.config.varUi['ActPointBackColor2'][0],
                    self.config.varUi['ActPointBackColor2'][1],
                    self.config.varUi['ActPointBackColor2'][2])
        if index == 0:
            self.pushButtonActPoint1.setStyleSheet(shell)
            self.labelActPointState1.setText(state_text)
            self.labelActPointTime1.setText(time_text)
        elif index == 1:
            self.pushButtonActPoint2.setStyleSheet(shell)
            self.labelActPointState2.setText(state_text)
            self.labelActPointTime2.setText(time_text)
        elif index == 2:
            self.pushButtonActPoint3.setStyleSheet(shell)
            self.labelActPointState3.setText(state_text)
            self.labelActPointTime3.setText(time_text)
        elif index == 3:
            self.pushButtonActPoint4.setStyleSheet(shell)
            self.labelActPointState4.setText(state_text)
            self.labelActPointTime4.setText(time_text)
        elif index == 4:
            self.pushButtonActPoint5.setStyleSheet(shell)
            self.labelActPointState5.setText(state_text)
            self.labelActPointTime5.setText(time_text)
        elif index == 5:
            self.pushButtonActPoint6.setStyleSheet(shell)
            self.labelActPointState6.setText(state_text)
            self.labelActPointTime6.setText(time_text)
        elif index == 6:
            self.pushButtonActPoint7.setStyleSheet(shell)
            self.labelActPointState7.setText(state_text)
            self.labelActPointTime7.setText(time_text)
        # print('%s-%s' % (state_text, time_text))
        # eval('self.pushButtonActPoint%d.setStyleSheet(\'%s\')' % (index + 1, shell))
        # eval('self.labelActPointState%d.setText(\'%s\')' % (index + 1, state_text))
        # eval('self.labelActPointTime%d.setText(\'%s\')' % (index + 1, time_text))

    # def getButtonAct(self, index):
    #     return 'self.pushButtonAct%d' % index

    def setButtonActText(self, index, text):
        eval('self.pushButtonAct%d.setText(\'%s\')' % (index, text))

    def setButtonActEnable(self, index, enable):
        eval('self.pushButtonAct%d.setEnabled(%s)' % (index, str(enable)))

    def setButtonActConnect(self, index):
        s = 'self.pushButtonAct%d.clicked.connect(partial(self.proc_act,%d))' % (index, index)
        eval(s)

    def init(self):
        self.setWindowFlags(Qt.WindowType.FramelessWindowHint)
        if self.config.varConf['WindowMax']:
            self.showMaximized()
        showLabel(self.labelLogo, LOGO)
        self.labelTitle.setText(' %s' % self.config.varConf['Title'])
        self.labelVer.setText('软件版本:%s' % VER)
        # ComboBox Height
        setComboBoxHeight(self.comboBoxComPort, 18)
        setComboBoxHeight(self.comboBoxComRate, 18)
        setComboBoxHeight(self.comboBoxActCodeFile, 18)
        setComboBoxHeight(self.comboBoxCodeAct, 18)
        setComboBoxHeight(self.comboBoxCodePara, 18)
        # 串口
        self.proc_com()
        self.isLink = False
        # 配置
        code_files = self.get_code_files()
        self.comboBoxActCodeFile.blockSignals(True)
        self.comboBoxActCodeFile.clear()
        self.comboBoxActCodeFile.addItems(code_files)
        self.comboBoxActCodeFile.blockSignals(False)
        # 冲洗按钮
        for i in range(7):
            self.setButtonActPointText(i)
            self.setButtonActPointEnable(i)
        for i in range(5):
            self.setButtonActText(i + 1, self.config.varUi['ButtonActText'][i])
            self.setButtonActEnable(i + 1, self.config.varUi['ButtonActEnable'][i])

    def flush_show(self):
        self.pushButtonExit.setEnabled(not self.isLink)
        self.pushButtonStop.setEnabled(self.isLink)
        self.pushButtonLink.setText('断开' if self.isLink else '连接')
        # SETUP
        self.comboBoxComPort.setEnabled(not self.isLink)
        self.pushButtonPortUp.setEnabled(not self.isLink)
        self.pushButtonPortDown.setEnabled(not self.isLink)
        self.pushButtonComFlush.setEnabled(not self.isLink)
        self.comboBoxComRate.setEnabled(not self.isLink)
        self.pushButtonRateUp.setEnabled(not self.isLink)
        self.pushButtonRateDown.setEnabled(not self.isLink)
        #
        self.doubleSpinBoxOriginCoordX.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxOriginCoordY.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxOriginCoordZ.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint1CoordX.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint1CoordY.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint1CoordZ1.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint1CoordZ2.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint2CoordX.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint2CoordY.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint2CoordZ1.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint2CoordZ2.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint3CoordX.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint3CoordY.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint3CoordZ1.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint3CoordZ2.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint4CoordX.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint4CoordY.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint4CoordZ1.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint4CoordZ2.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint5CoordX.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint5CoordY.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint5CoordZ1.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint5CoordZ2.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint6CoordX.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint6CoordY.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint6CoordZ1.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint6CoordZ2.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint7CoordX.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint7CoordY.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint7CoordZ1.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.doubleSpinBoxPoint7CoordZ2.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        #
        self.radioButtonArmRight.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.spinBoxArmRightPoint1.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.spinBoxArmRightPoint2.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.radioButtonArmLeft.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.spinBoxArmLeftPoint1.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.spinBoxArmLeftPoint2.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.spinBoxQuakeSpace.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.spinBoxJ4Pos.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.spinBoxJ4Rate.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.spinBoxXYRate.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        self.spinBoxZRate.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        #
        self.pushButtonSetupSave.setEnabled(not self.isLink or self.is_setup() and self.is_debug())
        # DEBUG
        self.pushButtonCodeRun.setEnabled(self.isLink and self.is_debug())
        self.pushButtonCodeRunStep.setEnabled(False)
        self.pushButtonMoveOrigin.setEnabled(self.isLink and self.is_debug())
        self.pushButtonMovePoint.setEnabled(self.isLink and self.is_debug())
        self.pushButtonMoveQuake.setEnabled(self.isLink and self.is_debug())
        self.pushButtonMoveRotate.setEnabled(self.isLink and self.is_debug())
        self.pushButtonMoveDelay.setEnabled(self.isLink and self.is_debug())
        self.pushButtonOutSw.setEnabled(self.isLink and self.is_debug())
        self.pushButtonCodeSelfCheck.setEnabled(self.isLink and self.is_debug())
        self.pushButtonCodeStop.setEnabled(self.isLink and self.is_debug())
        self.pushButtonCodeArm.setEnabled(self.isLink and self.is_debug())

        # self.comboBoxActCodeFile.setEnabled(self.isLink)
        # self.pushButtonActCodeFileLoad.setEnabled(self.isLink)
        # self.pushButtonActCodeFileNext.setEnabled(self.isLink)
        # 冲洗动作
        for i in range(5):
            self.setButtonActEnable(i + 1, self.isLink and self.config.varUi['ButtonActEnable'][i])

    def flush_debug(self):
        self.comboBoxCodeAct.blockSignals(True)
        self.comboBoxCodeAct.clear()
        self.comboBoxCodeAct.addItems(self.config.varCode['CodeList'])
        self.comboBoxCodeAct.blockSignals(False)
        self.comboBoxCodeAct.setCurrentText(self.config.varCode['CodeAct'])
        self.comboBoxCodePara.setCurrentIndex(self.config.varCode['CodePara'])
        self.spinBoxCodeMoveRate.setValue(self.config.varCode['CodeMoveRate'])
        self.checkBoxCodeMoveRateF.setChecked(self.config.varCode['CodeMoveRateF'])
        self.spinBoxCodeMoveSpace.setValue(self.config.varCode['CodeMoveSpace'])
        self.spinBoxCodeDelay.setValue(self.config.varCode['CodeDelay'])
        self.spinBoxCodeOut.setValue(self.config.varCode['CodeOut'])
        self.spinBoxCodeJ4Step.setValue(self.config.varCode['CodeJ4Step'])
        self.spinBoxCodeJ4Time.setValue(self.config.varCode['CodeJ4Time'])

    def flush_setup(self):
        self.pointList.clear()
        self.pointList.append(getPoint1(self.config.varSetup['OriginCoord']))
        self.doubleSpinBoxOriginCoordX.setValue(self.config.varSetup['OriginCoord'][0])
        self.doubleSpinBoxOriginCoordY.setValue(self.config.varSetup['OriginCoord'][1])
        self.doubleSpinBoxOriginCoordZ.setValue(self.config.varSetup['OriginCoord'][2])
        #
        self.pointList.append(getPoint1(self.config.varSetup['Point1Coord']))
        self.pointList.append(getPoint2(self.config.varSetup['Point1Coord']))
        self.doubleSpinBoxPoint1CoordX.setValue(self.config.varSetup['Point1Coord'][0])
        self.doubleSpinBoxPoint1CoordY.setValue(self.config.varSetup['Point1Coord'][1])
        self.doubleSpinBoxPoint1CoordZ1.setValue(self.config.varSetup['Point1Coord'][2])
        self.doubleSpinBoxPoint1CoordZ2.setValue(self.config.varSetup['Point1Coord'][3])
        #
        self.pointList.append(getPoint1(self.config.varSetup['Point2Coord']))
        self.pointList.append(getPoint2(self.config.varSetup['Point2Coord']))
        self.doubleSpinBoxPoint2CoordX.setValue(self.config.varSetup['Point2Coord'][0])
        self.doubleSpinBoxPoint2CoordY.setValue(self.config.varSetup['Point2Coord'][1])
        self.doubleSpinBoxPoint2CoordZ1.setValue(self.config.varSetup['Point2Coord'][2])
        self.doubleSpinBoxPoint2CoordZ2.setValue(self.config.varSetup['Point2Coord'][3])
        #
        self.pointList.append(getPoint1(self.config.varSetup['Point3Coord']))
        self.pointList.append(getPoint2(self.config.varSetup['Point3Coord']))
        self.doubleSpinBoxPoint3CoordX.setValue(self.config.varSetup['Point3Coord'][0])
        self.doubleSpinBoxPoint3CoordY.setValue(self.config.varSetup['Point3Coord'][1])
        self.doubleSpinBoxPoint3CoordZ1.setValue(self.config.varSetup['Point3Coord'][2])
        self.doubleSpinBoxPoint3CoordZ2.setValue(self.config.varSetup['Point3Coord'][3])
        #
        self.pointList.append(getPoint1(self.config.varSetup['Point4Coord']))
        self.pointList.append(getPoint2(self.config.varSetup['Point4Coord']))
        self.doubleSpinBoxPoint4CoordX.setValue(self.config.varSetup['Point4Coord'][0])
        self.doubleSpinBoxPoint4CoordY.setValue(self.config.varSetup['Point4Coord'][1])
        self.doubleSpinBoxPoint4CoordZ1.setValue(self.config.varSetup['Point4Coord'][2])
        self.doubleSpinBoxPoint4CoordZ2.setValue(self.config.varSetup['Point4Coord'][3])
        #
        self.pointList.append(getPoint1(self.config.varSetup['Point5Coord']))
        self.pointList.append(getPoint2(self.config.varSetup['Point5Coord']))
        self.doubleSpinBoxPoint5CoordX.setValue(self.config.varSetup['Point5Coord'][0])
        self.doubleSpinBoxPoint5CoordY.setValue(self.config.varSetup['Point5Coord'][1])
        self.doubleSpinBoxPoint5CoordZ1.setValue(self.config.varSetup['Point5Coord'][2])
        self.doubleSpinBoxPoint5CoordZ2.setValue(self.config.varSetup['Point5Coord'][3])
        #
        self.pointList.append(getPoint1(self.config.varSetup['Point6Coord']))
        self.pointList.append(getPoint2(self.config.varSetup['Point6Coord']))
        self.doubleSpinBoxPoint6CoordX.setValue(self.config.varSetup['Point6Coord'][0])
        self.doubleSpinBoxPoint6CoordY.setValue(self.config.varSetup['Point6Coord'][1])
        self.doubleSpinBoxPoint6CoordZ1.setValue(self.config.varSetup['Point6Coord'][2])
        self.doubleSpinBoxPoint6CoordZ2.setValue(self.config.varSetup['Point6Coord'][3])
        #
        self.pointList.append(getPoint1(self.config.varSetup['Point7Coord']))
        self.pointList.append(getPoint2(self.config.varSetup['Point7Coord']))
        self.doubleSpinBoxPoint7CoordX.setValue(self.config.varSetup['Point7Coord'][0])
        self.doubleSpinBoxPoint7CoordY.setValue(self.config.varSetup['Point7Coord'][1])
        self.doubleSpinBoxPoint7CoordZ1.setValue(self.config.varSetup['Point7Coord'][2])
        self.doubleSpinBoxPoint7CoordZ2.setValue(self.config.varSetup['Point7Coord'][3])
        #
        self.radioButtonArmRight.setChecked(self.config.varSetup['ArmRightMode'])
        self.spinBoxArmRightPoint1.setValue(self.config.varSetup['ArmRightPoint'][0])
        self.spinBoxArmRightPoint2.setValue(self.config.varSetup['ArmRightPoint'][1])
        #
        self.radioButtonArmLeft.setChecked(self.config.varSetup['ArmLeftMode'])
        self.spinBoxArmLeftPoint1.setValue(self.config.varSetup['ArmLeftPoint'][0])
        self.spinBoxArmLeftPoint2.setValue(self.config.varSetup['ArmLeftPoint'][1])
        #
        self.spinBoxQuakeSpace.setValue(self.config.varSetup['QuakeSpace'])
        self.spinBoxJ4Pos.setValue(self.config.varSetup['J4'][0])
        self.spinBoxJ4Rate.setValue(self.config.varSetup['J4'][1])
        self.spinBoxXYRate.setValue(self.config.varSetup['Rate'][0])
        self.spinBoxZRate.setValue(self.config.varSetup['Rate'][1])

    def init_ui(self):
        for i in range(3, -1, -1):
            widget = self.stackedWidget.widget(i)
            # print('%d->%s' % (i, widget.objectName()))
            if widget in self.wingetList:
                continue
            self.stackedWidget.removeWidget(widget)
            if widget == self.pageInfo:
                self.pushButtonInfo.hide()
            elif widget == self.pageSetup:
                self.pushButtonSetup.hide()
            elif widget == self.pageDebug:
                self.pushButtonDebug.hide()
        # 退出，急停，连接
        self.pushButtonExit.clicked.connect(self.system_close)
        self.pushButtonStop.clicked.connect(self.system_stop)
        self.pushButtonLink.clicked.connect(self.system_link)
        # 调试，操作，信息，设置
        index = 0
        if self.is_debug():
            self.pushButtonDebug.clicked.connect(self.change_debug_window)
            index += 1
        self.pushButtonAct.clicked.connect(self.change_act_window)
        index += 1
        if self.is_info():
            self.pushButtonInfo.clicked.connect(self.change_info_window)
            index += 1
        if self.is_setup():
            self.pushButtonSetup.clicked.connect(self.change_setup_window)
            index += 1
        # 窗口
        self.change_widget(self.curWin)
        # 端口，速率，配置
        self.comboBoxComPort.currentTextChanged.connect(self.select_port)
        self.comboBoxComPort.setCurrentText(self.comPort)
        self.pushButtonPortUp.clicked.connect(lambda: self.proc_port(-1))
        self.pushButtonPortDown.clicked.connect(lambda: self.proc_port(1))
        self.comboBoxComRate.currentTextChanged.connect(self.select_rate)
        self.comboBoxComRate.setCurrentText('%d' % self.comRate)
        self.pushButtonRateUp.clicked.connect(lambda: self.proc_rate(-1))
        self.pushButtonRateDown.clicked.connect(lambda: self.proc_rate(1))
        self.comboBoxActCodeFile.currentTextChanged.connect(self.select_cur_code)
        self.comboBoxActCodeFile.setCurrentText('%s' % self.curCodeFile)
        self.pushButtonActCodeFileLoad.clicked.connect(self.proc_act_file_load)
        self.pushButtonActCodeFileNext.clicked.connect(self.proc_code_pos)
        self.pushButtonComFlush.clicked.connect(self.proc_com)
        # 保存
        self.pushButtonSetupSave.clicked.connect(self.proc_setup_save)
        # 调试
        self.pushButtonCodeLoad.clicked.connect(self.proc_code_load)
        self.pushButtonCodeSave.clicked.connect(self.proc_code_save)
        self.pushButtonCodeCreate.clicked.connect(self.proc_code_create)
        self.pushButtonCodeRun.clicked.connect(self.proc_code_run)
        self.pushButtonCodeRunStep.clicked.connect(self.proc_code_run_step)
        self.pushButtonMoveOrigin.clicked.connect(self.proc_move_origin)
        self.pushButtonMovePoint.clicked.connect(self.proc_move_point)
        self.pushButtonMoveQuake.clicked.connect(self.proc_move_quake)
        self.pushButtonMoveRotate.clicked.connect(self.proc_move_rotate)
        self.pushButtonMoveDelay.clicked.connect(self.proc_move_delay)
        self.pushButtonOutSw.clicked.connect(self.proc_out_sw)
        self.pushButtonCodePrompt.clicked.connect(self.proc_code_start)
        self.pushButtonCodeSelfCheck.clicked.connect(self.proc_code_self_check)
        self.pushButtonCodeStop.clicked.connect(self.proc_code_stop)
        self.pushButtonCodeArm.clicked.connect(self.proc_code_arm)
        self.pushButtonCodeInsert.clicked.connect(self.proc_code_insert)
        self.pushButtonCodeDelete.clicked.connect(self.proc_code_delete)
        self.pushButtonCodeFileClear.clicked.connect(self.proc_code_file_clear)
        self.comboBoxCodeAct.currentTextChanged.connect(self.change_code_act)
        self.comboBoxCodePara.currentIndexChanged.connect(self.change_code_para)
        self.spinBoxCodeMoveRate.valueChanged.connect(self.change_code_move_rate)
        self.checkBoxCodeMoveRateF.stateChanged.connect(self.change_code_move_rateF)
        self.spinBoxCodeMoveSpace.valueChanged.connect(self.change_code_move_space)
        self.spinBoxCodeJ4Step.valueChanged.connect(self.change_code_j4_step)
        self.spinBoxCodeJ4Time.valueChanged.connect(self.change_code_j4_time)
        self.spinBoxCodeDelay.valueChanged.connect(self.change_code_delay)
        self.spinBoxCodeOut.valueChanged.connect(self.change_code_out)
        # 冲洗
        for i in range(5):
            self.setButtonActConnect(i + 1)
        # 编辑信号
        self.plainTextEditCode.textChanged.connect(self.text_change)
        self.plainTextEditCode.cursorPositionChanged.connect(self.text_change_position)
        self.plainTextEditCode.blockCountChanged.connect(self.text_change_block)
        # 日志
        self.checkBoxLogSave.stateChanged.connect(self.change_log_save)
        self.pushButtonLogClear.clicked.connect(self.proc_log_clear)

    def system_close(self):
        # 退出
        self.close_code()
        self.close_serial()
        self.close()

    def system_stop(self):
        # 急停:
        self.flush_show()
        self.serial_thread.send(send_stop(), ok=False)
        # self.serial_thread.send('M92 X0 Y0 Z0 I0', ok=False)

    def close_serial(self):
        if self.serial_thread is None:
            return
        self.serial_thread.stop()

    def init_serial_thread(self):
        if self.serial_thread is not None:
            return
        try:
            self.save_log('init_serial_thread [%s:%d]' % (self.comPort, self.comRate))
            self.serial_thread = SerialThread(self.comPort, self.comRate)  # 替换为你的串口和波特率
            self.serial_thread.data_send.connect(self.on_serial_send)
            self.serial_thread.data_recv.connect(self.on_serial_recv)
            self.serial_thread.error_occurred.connect(self.on_serial_error)
            self.serial_thread.change_queue.connect(self.on_serial_queue)
            self.serial_thread.change_state.connect(self.on_serial_state)
            self.serial_thread.finished.connect(self.on_serial_finished)
            self.serial_thread.start()
            self.isLink = True
            self.flush_show()
        except SerialException as e:
            self.serial_thread = None
            print('Serial Exception: %s' % e)

    def serial_send(self, datas):
        if not self.isLink:
            return
        # 发送指令
        for s in datas:
            self.serial_thread.write(s)

    def on_serial_recv(self, data):
        screen_print('serial recv [%s]' % data)
        self.update_log('recv [%s]' % data)

    def on_serial_send(self, data):
        screen_print('serial send [%s]' % data)
        self.update_log('send [%s]' % data)

    def on_serial_error(self, error):
        screen_print('serial error [%s]' % error)
        self.update_log('error [%s]' % error)
        self.close_serial()

    def on_serial_queue(self, qsize):
        self.labelSerialQueue.setText('队列:%d' % qsize)

    def on_serial_state(self, state):
        self.labelSerialState.setText('等待' if state else '空闲')

    def on_serial_finished(self):
        self.isLink = False
        self.serial_thread = None
        self.flush_show()
        screen_print('serial finished')

    def system_link(self):
        # 连接
        if not self.isLink:
            self.init_serial_thread()
            self.serial_send(send_link())
            self.arm_mode = 1
            self.act_move_point.clear()
            self.act_move_pos = 0
            self.set_arm()
            self.lcdNumberTime.display('0')
            self.lcdNumberCurTimeInfo.display('0')
            self.lineEditCurActInfo.setText('')
            self.lineEditCurLocateInfo.setText('')
            self.proc_log_clear()
            # 自检
            if self.config.varSetup['LinkCheck']:
                self.code_test_timer.start(3000)
        else:
            self.close_serial()

    def set_arm(self):
        # 换臂
        if self.arm_mode:
            self.radioButtonCodeRightArm.setChecked(True)
        else:
            self.radioButtonCodeLeftArm.setChecked(True)

    def proc_com(self):
        com_list = list_ports()
        self.comboBoxComPort.blockSignals(True)
        self.comboBoxComPort.clear()
        self.comboBoxComPort.addItems(com_list)
        self.comboBoxComPort.blockSignals(False)

    def proc_port(self, pos):
        if pos < 0:
            if self.comboBoxComPort.currentIndex() == 0:
                return
        else:
            if self.comboBoxComPort.currentIndex() == (self.comboBoxComPort.count() - 1):
                return
        self.comboBoxComPort.setCurrentIndex(self.comboBoxComPort.currentIndex() + pos)

    def select_port(self, port):
        # 选择端口
        if self.comPort != port:
            print('select_port %d' % port)
            self.comPort = port
            self.config.write('COM', 'ComPort', self.comPort)

    def proc_rate(self, pos):
        if pos < 0:
            if self.comboBoxComRate.currentIndex() == 0:
                return
        else:
            if self.comboBoxComRate.currentIndex() == (self.comboBoxComRate.count() - 1):
                return
        self.comboBoxComRate.setCurrentIndex(self.comboBoxComRate.currentIndex() + pos)

    def select_rate(self, rate):
        # 选择波特率
        if self.comRate != int(rate):
            print('select_rate %d' % rate)
            self.comRate = int(rate)
            self.config.write('COM', 'ComRate', self.comRate)

    def proc_act(self, index):
        # 冲洗动作
        print('proc_act [%d]' % index)
        if index == 1:
            # 上卷
            self.proc_move_origin()
        elif index == 2:
            # 判断是否加载
            if not self.isConfRun(self.plainTextEditCode.toPlainText().split('\n')):
                showBox(self, '非标准配置,请重新选择冲洗配置 ！！！')
                return
            # 冲洗
            self.proc_code_run()
        elif index == 3:
            # 动作3
            pass
        elif index == 4:
            # 动作4
            pass
        elif index == 5:
            # 动作5
            pass

    def proc_code_pos(self):
        curPos = self.comboBoxActCodeFile.currentIndex() + 1
        if curPos == self.comboBoxActCodeFile.count():
            curPos = 0
        self.comboBoxActCodeFile.setCurrentIndex(curPos)

    def select_cur_code(self, code):
        # 选择配置
        if self.curCodeFile != code:
            self.curCodeFile = code
            self.config.write('CODE', 'CurCodeFile', self.curCodeFile)
        self.labelCurConf.setText(' %s' % self.curCodeFile)

    def proc_act_file_load(self):
        # 加载冲洗配置
        print('proc_act_file_load [%s]' % self.curCodeFile)
        filename = self.get_code_file(self.curCodeFile)
        self.show_code_file(filename)

    def proc_setup_save(self):
        # 保存setup
        print('proc_setup_save')
        l = [self.doubleSpinBoxOriginCoordX.value(),
             self.doubleSpinBoxOriginCoordY.value(),
             self.doubleSpinBoxOriginCoordZ.value()]
        if self.config.varSetup['OriginCoord'] != l:
            self.config.varSetup['OriginCoord'] = l
            self.config.write('SETUP', 'OriginCoord', listToStr(l))
        l = [self.doubleSpinBoxPoint1CoordX.value(),
             self.doubleSpinBoxPoint1CoordY.value(),
             self.doubleSpinBoxPoint1CoordZ1.value(),
             self.doubleSpinBoxPoint1CoordZ2.value()]
        if self.config.varSetup['Point1Coord'] != l:
            self.config.varSetup['Point1Coord'] = l
            self.config.write('SETUP', 'Point1Coord', listToStr(l))
        l = [self.doubleSpinBoxPoint2CoordX.value(),
             self.doubleSpinBoxPoint2CoordY.value(),
             self.doubleSpinBoxPoint2CoordZ1.value(),
             self.doubleSpinBoxPoint2CoordZ2.value()]
        if self.config.varSetup['Point2Coord'] != l:
            self.config.varSetup['Point2Coord'] = l
            self.config.write('SETUP', 'Point2Coord', listToStr(l))
        l = [self.doubleSpinBoxPoint3CoordX.value(),
             self.doubleSpinBoxPoint3CoordY.value(),
             self.doubleSpinBoxPoint3CoordZ1.value(),
             self.doubleSpinBoxPoint3CoordZ2.value()]
        if self.config.varSetup['Point3Coord'] != l:
            self.config.varSetup['Point3Coord'] = l
            self.config.write('SETUP', 'Point3Coord', listToStr(l))
        l = [self.doubleSpinBoxPoint4CoordX.value(),
             self.doubleSpinBoxPoint4CoordY.value(),
             self.doubleSpinBoxPoint4CoordZ1.value(),
             self.doubleSpinBoxPoint4CoordZ2.value()]
        if self.config.varSetup['Point4Coord'] != l:
            self.config.varSetup['Point4Coord'] = l
            self.config.write('SETUP', 'Point4Coord', listToStr(l))
        l = [self.doubleSpinBoxPoint5CoordX.value(),
             self.doubleSpinBoxPoint5CoordY.value(),
             self.doubleSpinBoxPoint5CoordZ1.value(),
             self.doubleSpinBoxPoint5CoordZ2.value()]
        if self.config.varSetup['Point5Coord'] != l:
            self.config.varSetup['Point5Coord'] = l
            self.config.write('SETUP', 'Point5Coord', listToStr(l))
        l = [self.doubleSpinBoxPoint6CoordX.value(),
             self.doubleSpinBoxPoint6CoordY.value(),
             self.doubleSpinBoxPoint6CoordZ1.value(),
             self.doubleSpinBoxPoint6CoordZ2.value()]
        if self.config.varSetup['Point6Coord'] != l:
            self.config.varSetup['Point6Coord'] = l
            self.config.write('SETUP', 'Point6Coord', listToStr(l))
        l = [self.doubleSpinBoxPoint7CoordX.value(),
             self.doubleSpinBoxPoint7CoordY.value(),
             self.doubleSpinBoxPoint7CoordZ1.value(),
             self.doubleSpinBoxPoint7CoordZ2.value()]
        if self.config.varSetup['Point7Coord'] != l:
            self.config.varSetup['Point7Coord'] = l
            self.config.write('SETUP', 'Point7Coord', listToStr(l))
        self.config.write('SETUP', 'ArmRightMode',
                          self.radioButtonArmRight.isChecked())
        s = '%d,%d' % (self.spinBoxArmRightPoint1.value(), self.spinBoxArmRightPoint2.value())
        self.config.write('SETUP', 'ArmRightPoint', s)
        self.config.write('SETUP', 'ArmLeftMode',
                          self.radioButtonArmLeft.isChecked())
        s = '%d,%d' % (self.spinBoxArmLeftPoint1.value(), self.spinBoxArmLeftPoint2.value())
        self.config.write('SETUP', 'ArmLeftPoint', s)
        self.config.write('SETUP', 'QuakeSpace',
                          self.spinBoxQuakeSpace.value())
        s = '%d,%d' % (self.spinBoxJ4Pos.value(), self.spinBoxJ4Rate.value())
        self.config.write('SETUP', 'J4', s)
        s = '%d,%d' % (self.spinBoxXYRate.value(), self.spinBoxZRate.value())
        self.config.write('SETUP', 'Rate', s)
        self.config.writeFile()

    def curButton(self):
        return self.buttonList[self.curWin]

    # def curWidget(self):
    #     return self.windowList[self.curWin]

    def get_button_index(self, button):
        for i, b in enumerate(self.buttonList):
            if button == b:
                return i
        return 0

    def change_debug_window(self):
        # print('debug')
        self.change_widget(self.get_button_index(self.pushButtonDebug))

    def change_act_window(self):
        # print('act')
        self.change_widget(self.get_button_index(self.pushButtonAct))

    def change_info_window(self):
        # print('info')
        self.change_widget(self.get_button_index(self.pushButtonInfo))

    def change_setup_window(self):
        # print('setup')
        self.change_widget(self.get_button_index(self.pushButtonSetup))

    def change_widget(self, index):
        # 调试,冲洗,信息,设置
        # print('%d->%d' % (self.curWin, index))
        self.stackedWidget.setCurrentIndex(index)
        # if self.curWin != index:
        #     self.curWin = index
        #     self.config.write('UI', 'CurWin', self.curWin)
        self.curButton().setAutoFillBackground(True)  # 设置自动填充背景色
        self.labelCurWindow.setText(self.curButton().text())

    def show_act(self):
        for i in range(7):
            self.showButtonActPointState(i)

    def show_code_file(self, filename):
        name = os.path.splitext(os.path.basename(filename))[0]
        self.labelCurConf.setText(name)
        self.lineEditCodeFilename.setText(name)
        msg = read_msg(filename)
        self.plainTextEditCode.clear()
        self.plainTextEditCode.appendPlainText(msg)

    def proc_code_load(self):
        # 载入配置
        print("proc_code_load")
        option = QFileDialog.Options()
        filename, _ = QFileDialog.getOpenFileName(self,
                                                  " 选择配置 ",
                                                  CODE_PATH,
                                                  "配置文件(*.code)",
                                                  options=option
                                                  )
        if os.path.isfile(filename):
            self.show_code_file(filename)

    def get_code_file(self, file):
        return path_join(CODE_PATH, file + '.code')

    def proc_code_save(self):
        # 保存配置
        print("proc_code_save")
        file = self.get_code_file(self.lineEditCodeFilename.text().strip())
        save_msg(self.plainTextEditCode.toPlainText(), file, mode='w')

    def proc_code_create(self):
        # 建立配置
        print("proc_code_create")
        if self.lineEditCodeFilename.text().strip() == '':
            return
        file = self.get_code_file(self.lineEditCodeFilename.text().strip())
        if os.path.isfile(file):
            if not showBoxYes(self, "配置文件已存在，是否覆盖?  "):
                return
        save_msg(';********** %s **********' % now_date_str(), file, mode='w')
        self.show_code_file(file)

    def close_code(self):
        if self.code_test_timer is not None:
            self.code_test_timer.stop()
            del self.code_test_timer
        if self.code_act_timer is not None:
            self.code_act_timer.stop()
            del self.code_act_timer
        if self.code_timer is not None:
            self.code_timer.stop()
            del self.code_timer
        if self.isRunning():
            self.code_thread.stop()

    def isRunning(self):
        # 是否运行中
        return self.code_thread is not None

    def show_code_run_act(self, act_info):
        self.lineEditCurActInfo.setText(act_info)
        # self.code_thread.delayTime - (int(time.time()) - self.code_thread.beginTime)

    def show_code_run_time(self, time_info):
        self.lcdNumberCurTimeInfo.display(time_info)

    def show_code_run_locate(self, locate_info):
        self.lineEditCurLocateInfo.setText(locate_info)

    def set_quake(self, code_list):
        # 震动,index,space,time,rate
        print('set_quake')
        self.code_act_quake_state = 0  # 0-up,1-down
        self.code_act_quake_point, _, _ = self.get_code_point_locate(code_list[1])
        self.code_act_quake_space = code_list[2]
        self.code_act_ts = code_list[3]
        self.code_act_rate = code_list[4]

    def set_rotate(self, code_list):
        # 旋转,step,rate,time
        print('set_rotate')
        self.code_act_rotate_step = code_list[1]
        self.code_act_rate = code_list[2]
        self.code_act_ts = code_list[3]

    def set_act(self):
        # print('set_act')
        delay = self.config.varCode['CodeActDelay']
        self.code_act_state = 0
        if delay > 0:
            self.code_act_delay = True
            self.code_act_timer.start(delay)
            print('set_act %d' % delay)
        else:
            self.code_act_timer.start(self.code_act_ts)
            print('set_act %d' % self.code_act_ts)

    def init_act(self):
        self.code_act_state = -1
        self.code_act_delay = False
        self.code_act_rate = 0
        self.code_act_quake_state = 0
        self.code_act_quake_point = []  # 空无震动
        self.code_act_quake_space = 0
        self.code_act_rotate_step = 0  # 0 无旋转
        self.code_act_ts = 0

    def init_cur_act(self):
        # 当前位置信息
        self.act_cur_locate = 0
        self.act_cur_begin_time = 0
        self.act_cur_tims = [0, 0, 0, 0, 0, 0, 0]
        self.act_cur_state = [0, 0, 0, 0, 0, 0, 0]

    def on_proc_code(self, code_list):
        if len(code_list) == 0:
            # 运行结束
            for i in range(5):
                self.setButtonActEnable(i + 1, self.config.varUi['ButtonActEnable'][i])
            if self.is_debug():
                self.pushButtonCodeRun.setEnabled(True)
                # self.pushButtonCodeRunStep.setEnabled(True)
            # 结束
            self.code_thread = None
            if self.code_act_timer is not None:
                self.code_act_timer.stop()
            self.init_act()
            if self.code_timer is not None:
                self.code_timer.stop()
            self.flush_show()
            print("on_proc_code end")
            return
        # 指令动作
        # print("on_proc_code [%s]" % str(code_list))
        if code_list[0] == 0:
            # 移动,index,rate,m143
            self.act_move_point, self.act_move_pos, loc = self.get_code_point_locate(code_list[1])
            move_msg = '移动 %d %d' % (self.act_move_pos, code_list[1])
            self.show_code_run_act(move_msg)
            screen_print('%s loc %d %d' % (move_msg, loc, self.act_cur_locate))
            # if self.act_move_pos != self.act_cur_locate:
            if self.act_move_pos != 0 and loc != 0:
                # 非0点，下位点，位置改变
                if self.act_cur_locate != 0:
                    locate = self.act_cur_locate - 1
                    self.act_cur_tims[locate] = int(time.time()) - self.act_cur_begin_time
                    self.act_cur_state[locate] = 2
                    self.showButtonActPointState(locate, self.act_cur_state[locate], self.act_cur_tims[locate])
                    screen_print('locate %d time %d state %d' % (locate,
                                                                 self.act_cur_tims[locate],
                                                                 self.act_cur_state[locate]))
                self.act_cur_locate = self.act_move_pos
                self.act_cur_begin_time = int(time.time())
                self.act_cur_tims[self.act_cur_locate - 1] = 0
                self.act_cur_state[self.act_cur_locate - 1] = 1
                self.show_code_run_locate('%d-%d' % (self.act_cur_locate, loc))
                screen_print('show_code_run_locate %d %d' % (self.act_cur_locate, loc))

            rate = None
            m143 = False
            if len(code_list) > 2:
                rate = code_list[2]
            if len(code_list) > 3:
                m143 = code_list[3]
            self.send_move_code(self.act_move_point, rate=rate, m143=m143)
        elif code_list[0] == 1:
            # 震动,index,space,time,rate
            move_msg = '震动 %d %d %d' % (code_list[1], code_list[2], code_list[3])
            self.show_code_run_act(move_msg)
            self.set_quake(code_list)
        elif code_list[0] == 2:
            # 旋转,step,rate,time
            move_msg = '旋转 %d %d %d' % (code_list[1], code_list[2], code_list[3])
            self.show_code_run_act(move_msg)
            self.set_rotate(code_list)
        elif code_list[0] == 3:
            # 输出,port,sw
            move_msg = '输出 %d %d' % (code_list[1], code_list[2])
            self.show_code_run_act(move_msg)
            self.serial_send(send_out(code_list[1] - 1, code_list[2]))
        elif code_list[0] == 4:
            # 计时结束
            screen_print("code_act_state [%d]" % self.code_act_state)
            if self.code_act_state >= 0:
                # 计时结束
                self.code_act_timer.stop()
                self.init_act()
            else:
                # 开始计时等待
                self.set_act()
        elif code_list[0] == 5:
            # 停止,delay
            move_msg = '暂停 %d' % code_list[1]
            self.show_code_run_act(move_msg)
            self.proc_code_stop()
        elif code_list[0] == 6:
            # 换臂-arm
            move_msg = '换臂 %d' % code_list[1]
            self.show_code_run_act(move_msg)
            self.serial_send(send_arm(code_list[1]))

    def proc_code_timer(self):
        # 代码定时
        t_ms = time.perf_counter() - self.code_begin_time
        if self.isRunning():
            code_s = int(time.time()) - self.code_thread.beginTime
            locate = self.act_cur_locate - 1
            screen_print('proc_code_timer locate %d state %d' % (locate, self.act_cur_state[locate]))
            if locate >= 0:
                # X桶
                if self.config.varUi['ButtonPointEnable'][locate] and self.act_cur_state[locate] == 1:
                    self.act_cur_tims[locate] = int(time.time()) - self.act_cur_begin_time
                    screen_print('proc_code_timer locate %d %d %d %d %d' % (locate,
                                                                            self.act_cur_begin_time,
                                                                            self.act_cur_state[locate],
                                                                            self.act_cur_tims[locate],
                                                                            code_s))
                    self.showButtonActPointState(locate,
                                                 self.act_cur_state[locate],
                                                 self.act_cur_tims[locate])
            if self.code_thread.isWait and not self.code_thread.pauseMode:
                self.show_code_run_time('%d' % code_s)
            else:
                self.show_code_run_time('')
        else:
            self.show_code_run_time('')
        self.lcdNumberTime.display('%.2f' % t_ms)

    def proc_code_act_timer(self):
        # 震动+旋转定时
        if self.code_act_state < 0:
            self.code_act_timer.stop()
            self.init_act()
            return
        #
        if self.code_act_delay:
            # 延迟
            self.code_act_timer.stop()
            self.code_act_delay = False
            self.code_act_timer.start(self.code_act_ts)
            return
        act_point = []
        if len(self.code_act_quake_point) == 3:
            # 震动
            act_point.append(self.code_act_quake_point[0])
            act_point.append(self.code_act_quake_point[1])
            if self.code_act_quake_state:
                # down
                self.code_act_quake_state = 0
                act_point.append(self.code_act_quake_point[2])
            else:
                # up
                self.code_act_quake_state = 1
            act_point.append(self.code_act_quake_point[2] + self.code_act_quake_space)
        step = 0
        if self.code_act_rotate_step > 0:
            # 旋转
            step = self.code_act_rotate_step
        if len(act_point) > 0 or step > 0:
            self.serial_send(send_move2(act_point, step, self.code_act_rate, g92=True))

    # def proc_code_rotate_timer(self):
    #     # 震动定时
    #     code_s = self.code_thread.delayTime - int(time.time()) + self.code_thread.beginTime
    #     code_s *= 1000
    #     screen_print('timer send rotate %d %d %d %d %d' % (self.code_rotate_state,
    #                                                        self.code_rotate_step,
    #                                                        self.code_rotate_rate,
    #                                                        self.code_rotate_ts,
    #                                                        code_s
    #                                                        ))
    #     if self.code_rotate_state < 0:
    #         self.code_rotate_timer.stop()
    #         return
    #     if code_s > self.code_rotate_ts:
    #         self.serial_send(send_rotate(self.code_rotate_step,
    #                                      rate=self.code_rotate_rate,
    #                                      g92=True))
    def isConfRun(self, code_list):
        if len(code_list) < self.config.varCode['CodeConfRows']:
            # 配置行数大于50
            return False
        if code_list[0][0] == ':' and self.config.varCode['CodeConfWord'] in code_list[0]:
            return True
        return False

    def proc_code_run(self):
        # 运行
        print("proc_code_run")
        if self.is_debug():
            self.pushButtonCodeRun.setEnabled(False)
            # self.pushButtonCodeRunStep.setEnabled(False)
        for i in range(5):
            self.setButtonActEnable(i + 1, False)
        self.code_thread = codeThread(self.serial_thread,
                                      self.plainTextEditCode.toPlainText().split('\n')
                                      )
        self.code_thread.proc_code.connect(self.on_proc_code)
        if self.code_act_timer is None:
            # 震动+旋转
            self.code_act_timer = QTimer()
            self.code_act_timer.timeout.connect(self.proc_code_act_timer)
        if self.code_timer is None:
            # 计时
            self.code_timer = QTimer()
            self.code_timer.timeout.connect(self.proc_code_timer)
        # 初始动作
        self.proc_log_clear()
        self.init_act()
        self.init_cur_act()
        self.show_act()
        self.flush_show()
        self.code_begin_time = time.perf_counter()
        self.code_timer.start(self.config.varCode['CodeTimer'])
        self.code_thread.start()

    def proc_code_run_step(self):
        # 单步运行
        print("proc_code_run_step")

    def get_code_point_locate(self, index):
        point = [0.0, 0.0, 0.0]
        if index == 0:
            point[0] = self.config.varSetup['OriginCoord'][0]
            point[1] = self.config.varSetup['OriginCoord'][1]
            point[2] = self.config.varSetup['OriginCoord'][2]
            return point, 0, 0
        pos = int((index + 1) / 2)
        loc = (index + 1) % 2
        point[0] = self.config.varSetup['Point%dCoord' % pos][0]
        point[1] = self.config.varSetup['Point%dCoord' % pos][1]
        point[2] = self.config.varSetup['Point%dCoord' % pos][2 if index % 2 else 3]
        return point, pos, loc

    def show_move_point(self, point):
        self.doubleSpinBoxCoordX.setValue(point[0])
        self.doubleSpinBoxCoordY.setValue(point[1])
        self.doubleSpinBoxCoordZ.setValue(point[2])
        self.labelCurPoint.setText(' X%.2f, Y%.2f, Z%.2f' % (point[0], point[1], point[2]))

    def send_move_code(self, point, rate, m143):
        self.show_move_point(point)
        if rate:
            self.serial_send(send_move(point, rate=rate, m143=m143))
        else:
            self.serial_send(send_move(point, m143=m143))

    def proc_move_origin(self):
        # 原点
        print("proc_move_origin")
        self.arm_mode = 1
        self.act_move_point = copy.deepcopy(self.config.varSetup['OriginCoord'])
        self.act_move_pos = 0
        self.show_move_point(self.act_move_point)
        if self.checkBoxCodeMoveRateF.isChecked():
            self.serial_send(send_move0(self.act_move_point, rate=self.spinBoxCodeMoveRate.value()))
        else:
            self.serial_send(send_move0(self.act_move_point))

    def proc_move_point(self):
        # 移动坐标
        print("proc_move_point %d:%s" % (self.comboBoxCodePara.currentIndex(), self.comboBoxCodePara.currentText()))
        self.act_move_point, self.act_move_pos, _ = self.get_code_point_locate(self.comboBoxCodePara.currentIndex())
        # 臂转换
        if self.checkBoxCodeMoveRateF.isChecked():
            self.send_move_code(self.act_move_point,
                                rate=self.spinBoxCodeMoveRate.value(),
                                m143=self.checkBoxCodeMoveM143.isChecked())
        else:
            self.send_move_code(self.act_move_point, 0,
                                m143=self.checkBoxCodeMoveM143.isChecked())

    def proc_move_quake(self):
        # 震动+旋转
        print("proc_move_quake %d:%s %d-%d" % (self.comboBoxCodePara.currentIndex(),
                                               self.comboBoxCodePara.currentText(),
                                               self.spinBoxCodeMoveSpace.value(),
                                               self.spinBoxCodeJ4Time.value()))
        point, _, _ = self.get_code_point_locate(self.comboBoxCodePara.currentIndex())
        act_point = []
        # 震动
        act_point.append(point[0])
        act_point.append(point[1])
        if self.code_act_quake_state:
            # down
            self.code_act_quake_state = 0
            act_point.append(point[2])
        else:
            # up
            self.code_act_quake_state = 1
            act_point.append(point[2] + self.spinBoxCodeMoveSpace.value())
        step = 0
        if self.checkBoxCodeAct.isChecked():
            # 旋转
            step = self.spinBoxCodeJ4Step.value()
        self.serial_send(send_move2(act_point,
                                    step,
                                    self.spinBoxCodeMoveRate.value(),
                                    g92=True if step > 0 else False,
                                    m143=self.checkBoxCodeMoveM143.isChecked()))

    def proc_move_rotate(self):
        # 旋转
        print("proc_move_rotate %d %d %d" % (self.config.varSetup['J4'][0],
                                             self.spinBoxCodeJ4Step.value(),
                                             self.spinBoxCodeJ4Time.value()))
        self.serial_send(send_move2([],
                                    self.spinBoxCodeJ4Step.value(),
                                    self.spinBoxCodeMoveRate.value(),
                                    g92=True,
                                    m143=self.checkBoxCodeMoveM143.isChecked()))

    def proc_code_start(self):
        # 测试动作1
        # print("proc_code_start")
        self.win = StartRun(self.config.varConf['PromptImage'],
                            self.config.varConf['PromptText'])
        self.win.exec()

    def update_test_timer(self):
        self.code_test_timer.stop()
        self.proc_code_self_check()

    def proc_code_self_check(self):
        # 测试动作2
        print("proc_code_self_check")
        # 增加自检位置
        mode = self.config.varSetup['LinkMode']
        if mode == 0:
            self.proc_move_origin()
            return
        self.radioButtonCodeRightArm.setChecked(True)
        self.proc_code_arm()
        point, _, _ = self.get_code_point_locate(mode)
        self.serial_send(send_move(point, rate=3000, m143=True))
        point = copy.deepcopy(self.config.varSetup['OriginCoord'])
        self.serial_send(send_move0(point))

    def proc_code_stop(self):
        # 暂停-等待
        print("proc_code_stop")
        win = StopRun('请卸下冲洗罐', self.spinBoxCodeStopDelay.value(), self.serial_thread)
        win.proc_exit.connect(self.on_proc_stop_exit)
        win.exec()

    def on_proc_stop_exit(self, delay):
        print("on_proc_stop_exit %d" % delay)
        if self.code_thread is not None:
            self.code_thread.pause()

    def proc_code_arm(self):
        # 换臂
        self.arm_mode = 0 if self.radioButtonCodeLeftArm.isChecked() else 1
        print("proc_code_arm %d" % self.arm_mode)
        self.serial_send(send_arm(self.arm_mode))

    def proc_move_delay(self):
        # 延迟
        print("proc_move_delay %d %d" % (self.spinBoxCodeDelay,
                                         1 if self.radioButtonDelayBegin.isChecked() else 0))

    def proc_out_sw(self):
        # 开关
        sw = 1 if self.radioButtonCodeOutOn.isChecked() else 0
        print("proc_out_sw %d" % sw)
        self.serial_send(send_out(self.spinBoxCodeOut.value() - 1, sw))

    def proc_code_insert(self):
        # 插入代码
        print("proc_code_insert")
        act = self.comboBoxCodeAct.currentText()
        ret = isActType(act)
        if ret < 0:
            return
        codeDict = CODEDICT.copy()
        codeDict['code'] = act
        if ret == 0:
            # 移动
            codeDict['point'] = self.comboBoxCodePara.currentIndex()
            codeDict['rate'] = self.spinBoxCodeMoveRate.value()
            codeDict['m143'] = self.checkBoxCodeMoveM143.isChecked()
        elif ret == 1:
            # 震动
            codeDict['point'] = self.comboBoxCodePara.currentIndex()
            codeDict['rate'] = self.spinBoxCodeMoveRate.value()
            codeDict['space'] = self.spinBoxCodeMoveSpace.value()
            codeDict['time'] = self.spinBoxCodeJ4Time.value()
        elif ret == 2:
            # J4
            codeDict['step'] = self.spinBoxCodeJ4Step.value()
            codeDict['rate'] = self.spinBoxCodeMoveSpace.value()
            codeDict['time'] = self.spinBoxCodeJ4Time.value()
        elif ret == 3:
            # 输出
            codeDict['port'] = self.spinBoxCodeOut.value()
            codeDict['sw'] = 1 if self.radioButtonCodeOutOn.isChecked() else 0
        elif ret == 4:
            # 延迟
            codeDict['state'] = 'begin' if self.radioButtonDelayBegin.isChecked() else 'end'
            if codeDict['state'] == 'begin':
                codeDict['delay'] = self.spinBoxCodeDelay.value()
        elif ret == 5:
            # 暂停
            codeDict['delay'] = self.spinBoxCodeStopDelay.value()
        elif ret == 6:
            # 换臂
            if self.radioButtonCodeLeftArm.isChecked():
                codeDict['arm'] = 0
            else:
                codeDict['arm'] = 1
        # 指令转串
        self.plainTextEditCode.appendPlainText(str(codeDict))
        self.plainTextEditCode.moveCursor(QTextCursor.End)

    def proc_code_delete(self):
        # 插入代码
        # 获取所有行
        lines = self.plainTextEditCode.toPlainText().split('\n')
        # 删除指定行
        if 0 <= self.codeTextLine < len(lines):
            del lines[self.codeTextLine]
        # 重新组合并设置文本
        self.plainTextEditCode.setPlainText('\n'.join(lines))

    def proc_code_file_clear(self):
        self.lineEditCodeFilename.clear()

    def show_text_info(self):
        self.labelTextInfo.setText('%d,%d,%d' % (self.codeTextPos, self.codeTextLine, self.codeTextNums))

    def text_change(self):
        print("text_change")
        # self.show_text_info()

    def text_change_position(self):
        print("text_change_position")
        # 光标位置
        self.codeTextPos = self.plainTextEditCode.textCursor().position()
        self.codeTextLine = self.plainTextEditCode.document().findBlock(self.codeTextPos).blockNumber()
        self.show_text_info()

    def text_change_block(self, nums):
        print("text_change_block")
        self.codeTextNums = nums
        self.show_text_info()

    def change_code_act(self, act):
        # print(act)
        if self.config.varCode['CodeAct'] != act:
            self.config.varCode['CodeAct'] = act
            self.config.write('CODE', 'CodeAct', act)

    def change_code_para(self, para):
        if self.config.varCode['CodePara'] != para:
            self.config.varCode['CodePara'] = para
            self.config.write('CODE', 'CodePara', para)
        self.doubleSpinBoxCoordX.setValue(self.pointList[para][0])
        self.doubleSpinBoxCoordY.setValue(self.pointList[para][1])
        self.doubleSpinBoxCoordZ.setValue(self.pointList[para][2])

    def change_code_move_rate(self, para):
        if self.config.varCode['CodeMoveRate'] != para:
            self.config.varCode['CodeMoveRate'] = para
            self.config.write('CODE', 'CodeMoveRate', para)

    def change_code_move_space(self, para):
        if self.config.varCode['CodeMoveSpace'] != para:
            self.config.varCode['CodeMoveSpace'] = para
            self.config.write('CODE', 'CodeMoveSpace', para)

    def change_code_move_rateF(self, f):
        b = True if f == 2 else False
        if self.config.varCode['CodeMoveRateF'] != b:
            self.config.varCode['CodeMoveRateF'] = b
            self.config.write('CODE', 'CodeMoveRateF', b)

    def change_code_delay(self, para):
        if self.config.varCode['CodeDelay'] != para:
            self.config.varCode['CodeDelay'] = para
            self.config.write('CODE', 'CodeDelay', para)

    def change_code_out(self, para):
        if self.config.varCode['CodeOut'] != para:
            self.config.varCode['CodeOut'] = para
            self.config.write('CODE', 'CodeOut', para)

    def change_code_j4_step(self, para):
        if self.config.varCode['CodeJ4Step'] != para:
            self.config.varCode['CodeJ4Step'] = para
            self.config.write('CODE', 'CodeJ4Step', para)

    def change_code_j4_time(self, para):
        if self.config.varCode['CodeJ4Time'] != para:
            self.config.varCode['CodeJ4Time'] = para
            self.config.write('CODE', 'CodeJ4Time', para)

    # 信息窗口
    def change_log_save(self, save):
        if self.config.varCom['LogSave'] != save:
            self.config.varCode['LogSave'] = save
            self.config.write('COM', 'LogSave', save)

    def proc_log_clear(self):
        self.plainTextEditLog.clear()
        self.curLogRows = 0

    def save_log(self, msg):
        if self.checkBoxLogSave.isChecked():
            save_log(msg)

    def update_log(self, msg):
        self.plainTextEditLog.moveCursor(QTextCursor.Start)
        self.plainTextEditLog.insertPlainText(now_time_strf() + ' ' + msg + '\n')
        self.curLogRows += 1
        # self.log_rows_clean()

    # def log_last_clean(self):
    #     self.plainTextEditLog.setText(remove_last(self.plainTextEditLog.toPlainText()))
    #     self.curLogRows -= 1

    # def log_rows_clean(self):
    #     while self.curLogRows > self.config.varCom['LogRows']:
    #         self.log_last_clean()


# 代码运行
class codeThread(QThread):
    proc_code = pyqtSignal(list)

    def __init__(self, ser, code_list):
        super().__init__()
        self.ser = ser
        self.list = code_list
        self.pos = 0
        self.isStop = False
        self.pauseMode = 0
        self.pauseDelay = 600
        self.isWait = False
        self.isEmpty = False  # 等待空
        self.isQuake = False
        self.isRotate = False
        self.beginTime = 0
        self.delayTime = 0
        self.sleepTime = 0.15

    def run(self):
        self.start_time = time.perf_counter()
        while not self.isStop:
            # print('loop %d->%d %d %d' % (self.pos + 1,
            #                              len(self.list),
            #                              self.isWait,
            #                              self.pauseMode
            #                              ))
            if self.pauseMode > 0:
                # 暂停
                if self.pauseMode == 1:
                    # print('pause ser %d %d %d' % (self.ser.isEmpty(), self.ser.isOk, self.ser.isArrival))
                    if self.ser.isEmpty() and not self.ser.isOk and not self.ser.isArrival:
                        self.pause()
                        code_list = [5]
                        code_list.append(self.pauseDelay)
                        self.proc_code.emit(code_list)
                time.sleep(self.sleepTime)
                continue
            if self.isEmpty:
                # 等待发送空
                # print('empty ser %d %d %d' % (self.ser.isEmpty(), self.ser.isOk, self.ser.isArrival))
                if self.ser.isEmpty() and not self.ser.isOk and not self.ser.isArrival:
                    self.isEmpty = False
                time.sleep(self.sleepTime)
                continue
            if self.isWait:
                if (int(time.time()) - self.beginTime) > self.delayTime:
                    # 计时结束
                    self.isWait = False
                    code_list = [4]
                    self.proc_code.emit(code_list)
                else:
                    # 计时等待
                    time.sleep(self.sleepTime)
                continue
            if self.pos == len(self.list):
                # print('list end')
                break
            # if self.ser.isOk:
            #     continue
            if self.ser.isArrival:
                time.sleep(self.sleepTime)
                continue
            # pos = self.pos
            code = self.list[self.pos]
            act_type, act = isCodeType(code)
            self.pos += 1
            code_list = []
            if 0 <= act_type <= 7:
                # print('%d->%d:%s' % (pos + 1, act_type, code))
                if act_type == 0:
                    # 移动
                    code_list.append(0)
                    code_list.append(act['point'])
                    code_list.append(act['rate'])
                    if 'm143' in act.keys():
                        code_list.append(act['m143'])
                    else:
                        code_list.append(False)
                elif act_type == 1:
                    # 震动
                    code_list.append(1)
                    code_list.append(act['point'])
                    code_list.append(act['space'])
                    code_list.append(act['time'])
                    code_list.append(act['rate'])
                elif act_type == 2:
                    # 旋转
                    code_list.append(2)
                    code_list.append(act['step'])
                    code_list.append(act['rate'])
                    code_list.append(act['time'])
                elif act_type == 3:
                    # 输出
                    code_list.append(3)
                    code_list.append(act['port'])
                    code_list.append(act['sw'])
                elif act_type == 4:
                    # 计时
                    if act['state'] == 'begin':
                        # 计时设置
                        self.delayTime = act['delay']
                    else:
                        # 计时等待
                        self.beginTime = int(time.time())
                        self.isWait = True
                        code_list = [4]
                        self.proc_code.emit(code_list)
                        continue
                elif act_type == 5:
                    # 暂停
                    self.pauseDelay = act['delay']
                    self.pause()
                    continue
                elif act_type == 6:
                    # 换臂
                    code_list.append(6)
                    code_list.append(act['arm'])
                elif act_type == 7:
                    # 等待
                    self.isEmpty = True
                    continue
                # print(code_list)
            if act_type < 0 or len(code_list) == 0:
                time.sleep(self.sleepTime)
                continue
            if not self.isWait:
                if self.ser is None:
                    # 模拟
                    for i in range(20):
                        if self.isStop:
                            break
                        time.sleep(self.sleepTime)
                else:
                    # 发送指令
                    self.proc_code.emit(code_list)
        self.proc_code.emit([])

    def stop(self):
        # print('set stop')
        self.isStop = True

    def pause(self):
        if self.pauseMode == 2:
            self.pauseMode = 0
            self.pauseDelay = 0
        else:
            self.pauseMode += 1


if __name__ == '__main__':
    app = QApplication(sys.argv)

    main = FilmRun()
    main.show()

    sys.exit(app.exec_())
